home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / VIEWERS / X11 / XLOADIMG.TAR / xwd.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  15KB  |  502 lines

  1. /* xwd.c:
  2.  *
  3.  * XWD file reader.  unfortunately the bozo who thought up this format didn't
  4.  * define anything at all that we can use as an identifier or even to tell
  5.  * what kind of machine dumped the format.  what this does is read the
  6.  * header and look at several fields to decide if this *might* be an XWD
  7.  * file and if it is what byte order machine wrote it.
  8.  *
  9.  * jim frost 07.24.90
  10.  *
  11.  * Copyright 1990 Jim Frost.  See included file "copyright.h" for complete
  12.  * copyright information.
  13.  */
  14.  
  15. #include "copyright.h"
  16. #include "xloadimage.h"
  17. #include "xwd.h"
  18.  
  19. /* SUPPRESS 558 */
  20.  
  21. /* this reads the header and does the magic to determine if it is indeed
  22.  * an XWD file.
  23.  */
  24.  
  25. static int isXWD(name, zf, header, verbose)
  26.      char      *name;
  27.      ZFILE     *zf;
  28.      XWDHeader *header;
  29.      int        verbose;
  30. { GenericXWDHeader  gh;
  31.   int               a;
  32.  
  33.   if (zread(zf, (byte *)&gh, sizeof(GenericXWDHeader)) != sizeof(GenericXWDHeader))
  34.     return(0);
  35.  
  36.   /* first try -- see if XWD version number matches in either MSB or LSB order
  37.    */
  38.  
  39.   if (memToVal(gh.file_version, 4) != XWD_VERSION)
  40.     return(0);
  41.  
  42.   /* convert fields to fill out header.  things we don't care about
  43.    * are commented out.
  44.    */
  45.  
  46.   header->header_size= memToVal(gh.header_size, 4);
  47.   header->file_version= memToVal(gh.file_version, 4);
  48.   header->pixmap_format= memToVal(gh.pixmap_format, 4);
  49.   header->pixmap_depth= memToVal(gh.pixmap_depth, 4);
  50.   header->pixmap_width= memToVal(gh.pixmap_width, 4);
  51.   header->pixmap_height= memToVal(gh.pixmap_height, 4);
  52.   header->xoffset= memToVal(gh.xoffset, 4);
  53.   header->byte_order= memToVal(gh.byte_order, 4);
  54.   header->bitmap_unit= memToVal(gh.bitmap_unit, 4);
  55.   header->bitmap_bit_order= memToVal(gh.bitmap_bit_order, 4);
  56.   header->bitmap_pad= memToVal(gh.bitmap_pad, 4);
  57.   header->bits_per_pixel= memToVal(gh.bits_per_pixel, 4);
  58.   header->bytes_per_line= memToVal(gh.bytes_per_line, 4);
  59.   header->visual_class= memToVal(gh.visual_class, 4);
  60. /*header->red_mask= memToVal(gh.red_mask, 4);*/
  61. /*header->green_mask= memToVal(gh.green_mask, 4);*/
  62. /*header->blue_mask= memToVal(gh.blue_mask, 4);*/
  63. /*header->bits_per_rgb= memToVal(gh.bits_per_rgb, 4);*/
  64.   header->colormap_entries= memToVal(gh.colormap_entries, 4);
  65.   header->ncolors= memToVal(gh.ncolors, 4);
  66. /*header->window_width= memToVal(gh.window_width, 4);*/
  67. /*header->window_height= memToVal(gh.window_height, 4);*/
  68. /*header->window_x= memToVal(gh.window_x, 4);*/
  69. /*header->window_y= memToVal(gh.window_y, 4);*/
  70. /*header->window_bdrwidth= memToVal(gh.window_bdrwidth, 4);*/
  71.  
  72.   /* if header size isn't either 100 or 104 bytes, this isn't an XWD file
  73.    */
  74.  
  75.   if (header->header_size < sizeof(GenericXWDHeader))
  76.     return(0);
  77.  
  78.   for (a= header->header_size - sizeof(GenericXWDHeader); a; a--)
  79.     zgetc(zf);
  80.  
  81.   /* look at a variety of the XImage fields to see if they are sane.  if
  82.    * they are, this passes our tests.
  83.    */
  84.  
  85.   switch (header->pixmap_format) {
  86.   case XYBitmap:
  87.   case XYPixmap:
  88.   case ZPixmap:
  89.     break;
  90.   default:
  91.     return(0);
  92.   }
  93.  
  94.   switch (header->visual_class) {
  95.   case StaticGray:
  96.   case GrayScale:
  97.   case StaticColor:
  98.   case PseudoColor:
  99.  
  100.     /* the following are unsupported but recognized
  101.      */
  102.  
  103.   case TrueColor:
  104.   case DirectColor:
  105.     break;
  106.   default:
  107.     return(0);
  108.   }
  109.  
  110.   if (verbose) {
  111.     printf("%s is a %dx%d XWD image in ",
  112.        name, header->pixmap_width, header->pixmap_height);
  113.     switch (header->pixmap_format) {
  114.     case XYBitmap:
  115.       printf("XYBitmap");
  116.       break;
  117.     case XYPixmap:
  118.       printf("%d bit XYPixmap", header->pixmap_depth);
  119.       break;
  120.     case ZPixmap:
  121.       printf("%d bit ZPixmap", header->pixmap_depth);
  122.       break;
  123.     }
  124.     printf(" format\n");
  125.   }
  126.  
  127.   /* if it got this far, we're pretty damned certain we've got the right
  128.    * file type and know what order it's in.
  129.    */
  130.  
  131.   znocache(zf);
  132.   return(1);
  133. }
  134.  
  135. int xwdIdent(fullname, name)
  136.      char *fullname, *name;
  137. { ZFILE     *zf;
  138.   XWDHeader  header;
  139.   int ret;
  140.  
  141.   if (! (zf= zopen(fullname)))
  142.     return(0);
  143.   ret= isXWD(name, zf, &header, 1);
  144.   zclose(zf);
  145.   return(ret);
  146. }
  147.  
  148. static Image *loadXYBitmap(fullname, zf, header)
  149.      char *fullname;
  150.      ZFILE     *zf;
  151.      XWDHeader  header;
  152. { Image *image;
  153.   int    dlinelen;       /* length of scan line in data file */
  154.   int    ilinelen;       /* length of line within image structure */
  155.   int    unit;           /* # of bytes in a bitmap unit */
  156.   int    xoffset;        /* xoffset within line */
  157.   int    xunits;         /* # of units across the whole scan line */
  158.   int    trailer;        /* # of bytes in last bitmap unit on a line */
  159.   int    shift;          /* # of bits to shift last byte set */
  160.   int    x, y;           /* horizontal and vertical counters */
  161.   byte  *line;           /* input scan line */
  162.   byte  *dptr, *iptr;    /* image data pointers */
  163.   unsigned long (*loader)(); /* unit loading function */
  164.  
  165.   image= newBitImage(header.pixmap_width, header.pixmap_height);
  166.   ilinelen= (header.pixmap_width / 8) + (header.pixmap_width % 8 ? 1 : 0);
  167.   if (header.bitmap_unit > 7)     /* supposed to be 8, 16, or 32 but appears */
  168.     unit= header.bitmap_unit / 8; /* to often be the byte count.  this will */
  169.   else                            /* accept either. */
  170.     unit= header.bitmap_unit;
  171.   xoffset= (header.xoffset / (unit * 8)) * unit;
  172.   if (header.bytes_per_line)
  173.     dlinelen= header.bytes_per_line;
  174.   else
  175.     dlinelen= unit * header.pixmap_width;
  176.   xunits= (header.pixmap_width / (unit * 8)) +
  177.     (header.pixmap_width % (unit * 8) ? 1 : 0);
  178.   trailer= unit - ((xunits * unit) - ilinelen);
  179.   xunits--; /* we want to use one less than the actual # of units */
  180.   shift= (unit - trailer) * 8;
  181.   if (header.byte_order == MSBFirst)
  182.     loader= doMemToVal;
  183.   else
  184.     loader= doMemToValLSB;
  185.   line= (byte *)lmalloc(dlinelen);
  186.  
  187.   for (y= 0; y < header.pixmap_height; y++) {
  188.     if (zread(zf, (byte *)line, dlinelen) != dlinelen) {
  189.       fprintf(stderr,
  190.           "%s: Short read while reading data! (returning partial image)\n",
  191.           fullname);
  192.       lfree(line);
  193.       return(image);
  194.     }
  195.     dptr= line + xoffset;
  196.     iptr= image->data + (y * ilinelen);
  197.  
  198.     if (header.bitmap_bit_order == LSBFirst)
  199.       flipBits(line, dlinelen);
  200.  
  201.     for (x= 0; x < xunits; x++) {
  202.       valToMem(loader(dptr, unit), iptr, unit);
  203.       dptr += unit;
  204.       iptr += unit;
  205.     }
  206.  
  207.     /* take care of last unit on this line
  208.      */
  209.  
  210.     valToMem(loader(dptr, unit) >> shift, iptr, trailer);
  211.   }
  212.  
  213.   lfree(line);
  214.   return(image);
  215. }
  216.  
  217. /* this is a lot like the above function but OR's planes together to
  218.  * build the destination.  1-bit images are handled by XYBitmap.
  219.  */
  220.  
  221. static Image *loadXYPixmap(fullname, zf, header)
  222.      char *fullname;
  223.      ZFILE *zf;
  224.      XWDHeader header;
  225. { Image *image;
  226.   int plane;
  227.   int    dlinelen;       /* length of scan line in data file */
  228.   int    ilinelen;       /* length of line within image structure */
  229.   int    unit;           /* # of bytes in a bitmap unit */
  230.   int    unitbits;       /* # of bits in a bitmap unit */
  231.   int    unitmask;       /* mask for current bit within current unit */
  232.   int    xoffset;        /* xoffset within data */
  233.   int    xunits;         /* # of units across the whole scan line */
  234.   int    x, x2, y;       /* horizontal and vertical counters */
  235.   int    index;          /* index within image scan line */
  236.   byte  *line;           /* input scan line */
  237.   byte  *dptr, *iptr;    /* image data pointers */
  238.   unsigned long pixvals; /* bits for pixels in this unit */
  239.   unsigned long mask;
  240.   unsigned long (*loader)(); /* unit loading function */
  241.  
  242.   image= newRGBImage(header.pixmap_width, header.pixmap_height,
  243.              header.pixmap_depth);
  244.   ilinelen= image->width * image->pixlen;
  245.   if (header.bitmap_unit > 7)     /* supposed to be 8, 16, or 32 but appears */
  246.     unit= header.bitmap_unit / 8; /* to often be the byte count.  this will */
  247.   else                            /* accept either. */
  248.     unit= header.bitmap_unit;
  249.   unitbits= unit * 8;
  250.   unitmask= 1 << (unitbits - 1);
  251.   xoffset= (header.xoffset / unitbits) * unit;
  252.   if (header.bytes_per_line)
  253.     dlinelen= header.bytes_per_line;
  254.   else
  255.     dlinelen= unit * header.pixmap_width;
  256.   xunits= (header.pixmap_width / (unit * 8)) +
  257.     (header.pixmap_width % (unit * 8) ? 1 : 0);
  258.   if (header.byte_order == MSBFirst)
  259.     loader= doMemToVal;
  260.   else
  261.     loader= doMemToValLSB;
  262.   line= (byte *)lmalloc(dlinelen);
  263.  
  264.   /* for each plane, load in the bitmap and or it into the image
  265.    */
  266.  
  267.   for (plane= header.pixmap_depth; plane > 0; plane--) {
  268.     for (y= 0; y < header.pixmap_height; y++) {
  269.       if (zread(zf, (byte *)line, dlinelen) != dlinelen) {
  270.     fprintf(stderr,
  271.         "%s: Short read while reading data! (returning partial image)\n",
  272.         fullname);
  273.     lfree(line);
  274.     return(image);
  275.       }
  276.       dptr= line + xoffset;
  277.       iptr= image->data + (y * ilinelen);
  278.       index= 0;
  279.  
  280.       if (header.bitmap_bit_order == LSBFirst)
  281.     flipBits(line, dlinelen);
  282.       
  283.       for (x= 0; x < xunits; x++) {
  284.     pixvals= loader(dptr, unit);
  285.     mask= unitmask;
  286.     for (x2= 0; x2 < unitbits; x2++) {
  287.       if (pixvals & mask)
  288.         valToMem(memToVal(iptr + index, image->pixlen) | (1 << plane),
  289.              iptr + index, image->pixlen);
  290.       index += image->pixlen;
  291.       if (index > ilinelen) {
  292.         x= xunits;
  293.         break;
  294.       }
  295.       if (! (mask >>= 1))
  296.         mask= unitmask;
  297.     }
  298.     dptr += unit;
  299.       }
  300.     }
  301.   }
  302.  
  303.   lfree(line);
  304.   return(image);
  305. }
  306.  
  307. /* this loads a ZPixmap format image.  note that this only supports depths
  308.  * of 4, 8, 16, 24, or 32 bits as does Xlib.  You gotta 6-bit image,
  309.  * you gotta problem.  1-bit images are handled by XYBitmap.
  310.  */
  311.  
  312. static Image *loadZPixmap(fullname, zf, header)
  313.      char *fullname;
  314.      ZFILE *zf;
  315.      XWDHeader header;
  316. { Image *image;
  317.   int    dlinelen;       /* length of scan line in data file */
  318.   int    ilinelen;       /* length of scan line in image file */
  319.   int    depth;          /* depth rounded up to 8-bit value */
  320.   int    pixlen;         /* length of pixel in bytes */
  321.   int    x, y;           /* horizontal and vertical counters */
  322.   byte  *line;           /* input scan line */
  323.   byte  *dptr, *iptr;    /* image data pointers */
  324.   unsigned long pixmask; /* bit mask within pixel */
  325.   unsigned long pixel;   /* pixel we're working on */
  326.   unsigned long (*loader)(); /* unit loading function */
  327.  
  328.   image= newRGBImage(header.pixmap_width, header.pixmap_height,
  329.              header.pixmap_depth);
  330.  
  331.   /* for pixmaps that aren't simple depths, we round to a depth of 8.  this
  332.    * is what Xlib does, be it right nor not.
  333.    */
  334.  
  335.   if ((header.pixmap_depth != 4) && (header.pixmap_depth % 8))
  336.     depth= header.pixmap_depth + 8 - (header.pixmap_depth % 8);
  337.   else
  338.     depth= header.pixmap_depth;
  339.  
  340.   pixmask= 0xffffffff >> (32 - header.pixmap_depth);
  341.   pixlen= image->pixlen;
  342.   if (header.bytes_per_line)
  343.     dlinelen= header.bytes_per_line;
  344.   else
  345.     dlinelen= depth * header.pixmap_width;
  346.   ilinelen= image->width * image->pixlen;
  347.   if (header.byte_order == MSBFirst)
  348.     loader= doMemToVal;
  349.   else
  350.     loader= doMemToValLSB;
  351.  
  352.   line= (byte *)lmalloc(dlinelen);
  353.  
  354.   for (y= 0; y < header.pixmap_height; y++) {
  355.     if (zread(zf, (byte *)line, dlinelen) != dlinelen) {
  356.       fprintf(stderr,
  357.           "%s: Short read while reading data! (returning partial image)\n",
  358.           fullname);
  359.       lfree(line);
  360.       return(image);
  361.     }
  362.     dptr= line;
  363.     iptr= image->data + (y * ilinelen);
  364.  
  365.     if (header.bitmap_bit_order == LSBFirst)
  366.       flipBits(line, dlinelen);
  367.  
  368.     for (x= 0; x < header.pixmap_width; x++) {
  369.       switch (depth) {
  370.       case 4:
  371.     pixel= memToVal(dptr, 1);
  372.     if (header.bitmap_bit_order == LSBFirst) { /* nybbles are reversed */
  373.       valToMem(pixel & 0xf, iptr++, 1);        /* by flipBits */
  374.       if (++x < header.pixmap_width)
  375.         valToMem(pixel >> 4, iptr++, 1);
  376.     }
  377.     else {
  378.       valToMem(pixel >> 4, iptr++, 1);
  379.       if (++x < header.pixmap_width)
  380.         valToMem(pixel & 0xf, iptr++, 1);
  381.     }
  382.     break;
  383.       case 8:
  384.     pixel= ((unsigned long)*(dptr++)) & pixmask; /* loader isn't needed */
  385.     valToMem(pixel, iptr++, 1);
  386.     break;
  387.       case 16:
  388.       case 24:
  389.       case 32:
  390.     valToMem(loader(dptr, pixlen) & pixmask, iptr, pixlen);
  391.     dptr += pixlen;
  392.     iptr += pixlen;
  393.     break;
  394.       default:
  395.     fprintf(stderr,
  396.         "%s: ZPixmaps of depth %d are not supported (sorry).\n",
  397.         fullname, header.pixmap_depth);
  398.     exit(1);
  399.       }
  400.     }
  401.   }
  402.  
  403.   lfree(line);
  404.   return(image);
  405. }
  406.  
  407. Image *xwdLoad(fullname, name, verbose)
  408.      char *fullname, *name;
  409.      int verbose;
  410. { ZFILE     *zf;
  411.   XWDHeader  header;
  412.   int        cmaplen;
  413.   XWDColor  *cmap;
  414.   Image     *image;
  415.   int        a;
  416.  
  417.   if (! (zf= zopen(fullname)))
  418.     return(NULL);
  419.   if (! isXWD(name, zf, &header, verbose)) {
  420.     zclose(zf);
  421.     return(NULL);
  422.   }
  423.  
  424.   /* complain if we don't understand the visual
  425.    */
  426.  
  427.   switch (header.visual_class) {
  428.   case StaticGray:
  429.   case GrayScale:
  430.   case StaticColor:
  431.   case PseudoColor:
  432.     break;
  433.   case TrueColor:
  434.   case DirectColor:
  435.     fprintf(stderr, "Unsupported visual type, sorry\n");
  436.     exit(1);
  437.   }
  438.  
  439.   if ((header.pixmap_width == 0) || (header.pixmap_height == 0)) {
  440.     fprintf(stderr, "Zero-size image -- header might be corrupted.\n");
  441.     exit(1);
  442.   }
  443.  
  444.   /* read in colormap
  445.    */
  446.  
  447.   cmaplen= header.ncolors * sizeof(XWDColor);
  448.   cmap= (XWDColor *)lmalloc(cmaplen);
  449.   if (zread(zf, (byte *)cmap, cmaplen) != cmaplen) {
  450.     fprintf(stderr, "Short read in colormap!\n");
  451.     exit(1);
  452.   }
  453.  
  454.   /* any depth 1 image is basically a XYBitmap so we fake it here
  455.    */
  456.  
  457.   if (header.pixmap_depth == 1)
  458.     header.pixmap_format= XYBitmap;
  459.  
  460.   /* we can't realistically support images of more than depth 16 with the
  461.    * RGB image format so this nukes them for the time being.
  462.    */
  463.  
  464.   if (header.pixmap_depth > 16) {
  465.     fprintf(stderr,
  466.         "%s: Sorry, cannot load images deeper than 16 bits (yet)\n",
  467.         fullname);
  468.     exit(1);
  469.   }
  470.  
  471.   switch (header.pixmap_format) {
  472.   case XYBitmap:
  473.     image= loadXYBitmap(fullname, zf, header);
  474.     zclose(zf);
  475.     image->title= dupString(name);
  476.     return(image); /* we used to goof w/ the cmap but we gave up */
  477.   case XYPixmap:
  478.     image= loadXYPixmap(fullname, zf, header);
  479.     break;
  480.   case ZPixmap:
  481.     image= loadZPixmap(fullname, zf, header);
  482.     break;
  483.   }
  484.   zclose(zf);
  485.   image->title= dupString(name);
  486.  
  487.   /* load the colormap.  we should probably use pixval instead of the color
  488.    * number but the value seems pretty system-dependent and most colormaps
  489.    * seem to be just dumped in order.
  490.    */
  491.  
  492.   image->rgb.used= header.ncolors;
  493.   for (a= 0; a < header.ncolors; a++) {
  494.     image->rgb.red[memToVal(cmap[a].pixel, 4)]= memToVal(cmap[a].red, 2);
  495.     image->rgb.green[memToVal(cmap[a].pixel, 4)]= memToVal(cmap[a].green, 2);
  496.     image->rgb.blue[memToVal(cmap[a].pixel, 4)]= memToVal(cmap[a].blue, 2);
  497.   }
  498.  
  499.   lfree((byte *)cmap);
  500.   return(image);
  501. }
  502.